package controller;

import gui.JMessageDialog;
import gui.JRowItem;
import gui.Main;
import interfaces.ICIA;

import java.awt.GridLayout;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.security.PublicKey;
import java.util.ArrayList;
import java.util.List;

import javax.swing.JButton;
import javax.swing.JOptionPane;
import javax.swing.JPanel;

import api.CAUtils;
import api.CIA;

/**
 * @author hqthai01 Jan 2, 2015
 */
public class BtnDecryptAction implements ActionListener {

	private Main gui;
	private int count_dec = 0;
	private JPanel pn;
	private GridLayout grid;
	private JButton btnDecrypt;
	private Thread thread;
	private ICIA cia;
	private JMessageDialog errorMessage;

	public BtnDecryptAction(Main gui) {
		this.gui = gui;
		this.pn = this.gui.getPnListProcessDec();
		this.grid = this.gui.getGrid_dec();
		this.btnDecrypt = this.gui.getBtnDecrypt();
		this.cia = new CIA();
		this.listError = new ArrayList<String>();
		errorMessage = new JMessageDialog(gui, true);
	}

	@Override
	public void actionPerformed(ActionEvent e) {
		if (!isEmpty(gui.getTfCertificate().getText(), gui.getTfInputCert().getText(), gui.getTfOutputCert().getText())) {
			btnDecrypt.setEnabled(false);
			thread = new Thread(doDecrypt);
			thread.start();
		}
	}

	private Runnable doDecrypt = new Runnable() {
		@Override
		public void run() {
			try {
				PublicKey pubkey = getPublicKey();
				if (pubkey != null) {
					File inputFile = new File(gui.getTfInputCert().getText());
					if (inputFile.exists()) {
						boolean isDirectory = inputFile.isDirectory();
						String outFolder = gui.getTfOutputCert().getText();
						if (isDirectory) {
							JRowItem rowHeader = new JRowItem();
							rowHeader.setFileName("-----------BEGIN----------");
							addCompsDec(rowHeader);

							decryptFolder(inputFile, outFolder, pubkey);

							JRowItem rowFooter = new JRowItem();
							rowFooter.setFileName("-----------DONE----------");
							addCompsDec(rowFooter);
						} else {
							System.out.println(2);
							JRowItem rowHeader = new JRowItem();
							rowHeader.setFileName("-----------BEGIN----------");
							addCompsDec(rowHeader);

							File fileOut = new File(outFolder + "/" + inputFile.getName());
							if (!fileOut.getParentFile().exists())
								fileOut.getParentFile().mkdirs();
							decryptFile(pubkey, inputFile, fileOut);

							JRowItem rowFooter = new JRowItem();
							rowFooter.setFileName("-----------DONE----------");
							addCompsDec(rowFooter);
						}
						if(!listError.isEmpty()){
							String message = "File(s) cannot be decrypt because of your public key is invalid or the file(s) isn't encrypted\nSee the list of error file below";
							errorMessage.setMessage(message);
							errorMessage.setErrors(listError);
							errorMessage.setVisible(true);
							while(!listError.isEmpty()){
								listError.remove(0);
							}
						}else{
							JOptionPane.showMessageDialog(gui, "Your file(s) is decrypted", "message", JOptionPane.INFORMATION_MESSAGE);
						}
					} else {
						JOptionPane.showMessageDialog(gui, "Your input file is not exist", "Message", JOptionPane.ERROR_MESSAGE);
					}
				} else {
					JOptionPane.showMessageDialog(gui, "Your public key file is invalid", "Message", JOptionPane.ERROR_MESSAGE);
				}
				btnDecrypt.setEnabled(true);
				thread.join();
			} catch (Exception e) {
//				e.printStackTrace();
			}
		}
	};

	private boolean isEmpty(String... values) {
		for (int i = 0; i < values.length; i++) {
			if (values[i].equals(""))
				return true;
		}
		return false;
	}

	private PublicKey getPublicKey() {
		try {
			return CAUtils.getPublicKey(gui.getTfCertificate().getText());
		} catch (Exception e) {
//			e.printStackTrace();
			return null;
		}
	}

	private void decryptFolder(File inputFile, String folderOut, PublicKey pubkey) {
		File fileOut = new File(folderOut);
		if (inputFile.isDirectory()) {
			fileOut.mkdirs();
		}

		if (inputFile.isFile()) {
			decryptFile(pubkey, inputFile, fileOut);
		} else if (inputFile.isDirectory()) {
			File[] list = inputFile.listFiles();
			if (list.length > 0) {
				for (File file : list) {
					decryptFolder(file, folderOut + "/" + file.getName(), pubkey);
				}
			}
		}
	}

	private List<String> listError;

	private void decryptFile(PublicKey pubkey, File inputFile, File outputFile) {
		boolean error = false;
		JRowItem row = new JRowItem();
		row.setFileName(inputFile.getName());
		addCompsDec(row);
		try {
			cia.CIADecrypter(inputFile, outputFile, pubkey);
		} catch (Exception e) {
			listError.add(inputFile.getName());
			error = true;
		}
		
		if(error){
			row.setPercent("failed");
		}else{
			row.setPercent("decrypted");
		}
		row.revalidate();
	}

	private void addCompsDec(JRowItem rowItem) {
		count_dec++;
		updateCapicityDec();
		pn.add(rowItem);
		pn.revalidate();
		pn.scrollRectToVisible(new Rectangle(0, pn.getHeight(), 10, 10));
	}

	private void updateCapicityDec() {
		if (count_dec > 10) {
			grid.setRows(grid.getRows() + 1);
		}
	}
}
